package com.lanou.list;

/**
 * @author zyj
 * @date 2022年05月19日 9:16
 */
public class LinkedList<E> extends AbstractList<E> implements List<E> {
    private Node<E> first;
    private Node<E> last;
    private static final int ELEMENT_NOT_FOUND = -1;

    private class Node<E> {
        Node<E> prev;
        E item;
        Node<E> next;

        public Node(Node<E> prev, E item, Node<E> next) {
            this.prev = prev;
            this.item = item;
            this.next = next;
        }
    }

    /**
     * 获取双向链表的头节点
     *
     * @return
     */
    public Node<E> getFirst() {
        return first;
    }

    /**
     * 获取双向链表的尾节点
     *
     * @return
     */
    public Node<E> getLast() {
        return last;
    }


    @Override
    public E get(int index) {
        checkElementIndex(index);
        Node<E> node = node(index);
        return node.item;
    }


    private Node<E> node(int index) {
        Node<E> x = null;
        if (index < (size >> 1)) {
            x = first;
            for (int i = 0; i < index; i++) {
                x = x.next;
            }
        } else {
            x = last;
            for (int i = size - 1; i > index; i--) {
                x = x.prev;
            }
        }
        return x;
    }

    @Override
    public E set(int index, E element) {
        Node<E> node = node(index);
        E oldItem = node.item;
        node.item = element;
        return oldItem;
    }

    @Override
    public void add(int index, E element) {
        checkPositionIndex(index);
        //第一次添加元素或者往末尾添加元素
        if (index == size) {
            Node<E> l = last;
            Node<E> newNode = new Node<>(l, element, null);
            last = newNode;
            if (l == null) { //第一次添加元素
                first = last;
            } else {
                l.next = newNode; //往末尾添加元素
            }
            size++;
        } else {
            Node<E> cur = node(index);
            Node<E> prev = cur.prev;

            Node<E> newNode = new Node<>(prev, element, cur);
            if (null == prev) {
                first = newNode;
            } else {
                prev.next = newNode;
            }
            cur.prev = newNode;
        }
    }

    @Override
    public E remove(int index) {
        checkElementIndex(index);
        Node<E> cur = node(index);
        Node<E> prev = cur.prev;
        Node<E> next = cur.next;
        //prev:null 移除的第一个节点
        if (null == prev) {
            first = next;
        } else {
            prev.next = cur.next;
            cur.prev = null;
        }
        //next：null 移除的是最后一个节点
        if (null == next) {
            last = prev;
        } else {
            next.prev = cur.prev;
            cur.next = null;
        }
        E e = cur.item;
        cur.item = null;
        size--;
        return e;
    }

    @Override
    public int indexOf(E element) {
        int index = 0;
        if (null == element) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (null == x.item) {
                    return index;
                }
                index++;
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (element.equals(x.item)) {
                    return index;
                }
                index++;
            }
        }
        return ELEMENT_NOT_FOUND;
    }

    @Override
    public void clear() {
        for (Node<E> x = first; x != null; ) {
            Node<E> next = x.next;
            x.prev = null;
            x.item = null;
            x.next = null;
            x = next;
        }
        first = last = null;
        size = 0;
    }


    private void checkElementIndex(int index) {
        if (!isElementIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
    }

    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }
}
